package bogus.userInput;

import static bogus.core.BogusCore.panel;

import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.LinkedHashSet;

import bogus.core.BogusCore;

public enum Input implements AWTEventListener, MouseListener, MouseMotionListener {
    INSTANCE;

    public static final int maxKey = 128;
    public static final int maxButton = 4;

    private static boolean[] pressed;
    private static boolean[] clicked;

    public static int mouseX;
    public static int mouseY;

    public static float normalizedMouseX;
    public static float normalizedMouseY;

    private static LinkedHashSet<KeyListener> keyListeners = new LinkedHashSet<>();

    public static int[] framePressed;
    public static int[] frameClicked;

    public static Dimension preferredMouseDimension = new Dimension(864, 486);

    public static void setConstants(Dimension mouseDimension){
	preferredMouseDimension = mouseDimension;
	Point mousePosition = MouseInfo.getPointerInfo().getLocation();
	MouseEvent e = new MouseEvent(panel, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), getModifierMask(), 
		mousePosition.x-panel.getLocationOnScreen().x, mousePosition.y-panel.getLocationOnScreen().y, mousePosition.x, mousePosition.y, 
		0, false, MouseEvent.NOBUTTON);
	INSTANCE.mouseMoved(e);
    }

    public static void registerKeyboard() {
	Toolkit.getDefaultToolkit().addAWTEventListener(INSTANCE, AWTEvent.KEY_EVENT_MASK);

	pressed = new boolean[maxKey];
	clicked = new boolean[maxButton];

	framePressed = new int[maxKey];
	for (int i=0; i<maxKey; i++){
	    framePressed[i] = 0;
	}
    }
    public static void registerMouse(Component eventSource) {
	eventSource.addMouseListener(INSTANCE);
	eventSource.addMouseMotionListener(INSTANCE);
	frameClicked = new int[maxButton];
	for (int i=0; i<maxButton; i++){
	    frameClicked[i] = 0;
	}
    }

    /**call this once per step!!!!*/
    public static void framePressRefresh(){
	for (int i=0; i<maxKey; i++){
	    if (checkKey(i)){
		if (framePressed[i] == 0)
		    framePressed[i] = 2;
		else
		    framePressed[i] = 1;
	    }
	    else
		framePressed[i] = 0;
	}

	for (int i=0; i<maxButton; i++){
	    if (checkButton(i)){
		if (frameClicked[i] == 0)
		    frameClicked[i] = 2;
		else
		    frameClicked[i] = 1;
	    }
	    else
		frameClicked[i] = 0;
	}
    }

    /**check if a key was JUST PRESSED on this frame*/
    public static boolean checkFrameKey(int keyCode){
	return framePressed[keyCode] == 2;
    }

    /**check if a button was JUST CLICKED on this frame*/
    public static boolean checkFrameButton(int btnCode){
	return frameClicked[btnCode] == 2;
    }

    /**check if a key is being pressed/held*/
    public static boolean checkKey(int keyCode){
	if(keyCode>=maxKey){
	    System.err.println("Unsupported key");
	    return false;
	}

	return pressed[keyCode];
    }

    /**check if ANY KEY is being held/pressed*/
    public static boolean checkAnyKey(){
	for (int i=0; i<maxKey; i++){
	    if (checkKey(i))
		return true;
	}
	return false;
    }

    public static String inputString(){
	for (int i=0; i<maxKey; i++){
	    int keyInt = i;
	    if (checkKey(i) && ((keyInt>=65 && keyInt<=90)||(keyInt>=97 && keyInt<=122)))
		return ""+(char)keyInt;
	}
	return "";
    }

    @Override
    public void mouseClicked(MouseEvent arg0) {}

    @Override
    public void mouseEntered(MouseEvent arg0) {}

    @Override
    public void mouseExited(MouseEvent arg0) {}

    @Override
    public void mousePressed(MouseEvent e) {
	int k = e.getButton();
	if(k<maxButton)
	    clicked[k] = true;
    }

    @Override
    public void mouseReleased(MouseEvent e) {
	int k = e.getButton();
	if(k<maxButton)
	    clicked[k] = false;
    }

    /**check if a mouse button is pressed*/
    public static boolean checkButton(int button){
	return clicked[button];
    }

    @Override
    public void mouseDragged(MouseEvent e) {
	updateMousePosition(e);
    }

    @Override
    public void mouseMoved(MouseEvent e) {
	updateMousePosition(e);
    }

    public void updateMousePosition(MouseEvent e){
	mouseX = (e.getX() *preferredMouseDimension.width) / (BogusCore.panel.getWidth());
	mouseY = (e.getY() *preferredMouseDimension.height) / (BogusCore.panel.getHeight());
	normalizedMouseX = (float)e.getX() / (BogusCore.panel.getWidth());
	normalizedMouseY = (float)e.getY() / (BogusCore.panel.getHeight());
    }

    public static int getModifierMask()
    {
	int mask = 0;
	if(pressed[KeyEvent.VK_CONTROL])
	    mask |= KeyEvent.CTRL_DOWN_MASK;
	if(pressed[KeyEvent.VK_ALT])
	    mask |= KeyEvent.ALT_DOWN_MASK;
	if(pressed[KeyEvent.VK_SHIFT])
	    mask |= KeyEvent.SHIFT_DOWN_MASK;
	return mask;
    }

    @Override
    public void eventDispatched(AWTEvent ae)
    {
	KeyEvent e = (KeyEvent)ae;
	if(e.getID() == KeyEvent.KEY_PRESSED) {
	    int k = e.getKeyCode();
	    if(k<maxKey)
		pressed[k] = true;
	    for(KeyListener l : keyListeners)
		l.keyPressed(e);
	}
	else if(e.getID() == KeyEvent.KEY_RELEASED) {
	    int k = e.getKeyCode();
	    if(k<maxKey)
		pressed[k] = false;
	    for(KeyListener l : keyListeners)
		l.keyReleased(e);
	}
	else if(e.getID() == KeyEvent.KEY_TYPED)
	    for(KeyListener l : keyListeners)
		l.keyTyped(e);
    }

    public static void addKeyListener(KeyListener lis) {
	keyListeners.add(lis);
    }
    public static void removeKeyListener(KeyListener lis) {
	keyListeners.remove(lis);
    }

}
